/*
 * @Author: 0x9DEFA478
 * @Date: 2022-01-28 19:57:40
 * @LastEditTime: 2022-08-20 23:48:36
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * QQ:2652450237
 * ============================================================================================================================================
 * 
 * 
 * 
 *                                                                                               ************      ****************************
 *                                                                                             ************      ****************************  
 *                                                                                           ************      ****************************    
 *                                                                                         ************      ****************************      
 *                                                                                       ************      ************                        
 *                                                                                     ************      ************                          
 *                                                                                   ************      ************                            
 *                                                                                 ************      ************                              
 *                                                                               ************      ************                                
 *                                                                             ************      ************                                  
 *                                                                           ************      ************                                    
 *                                                                         ************      ************                                      
 *                                                                       ************      ************                                        
 *                                                                     ************      ************                                          
 *                                                                   ************      ************                                            
 *                                                                 ************      ************                                              
 *                                                               ************      ************                                                
 *                                                             ************      ************                                                  
 *                                                           ************      ************                                                    
 *                                                         ************      ************                                                      
 *                                                       ************      ************                                                        
 *                                                     ************      ************                                                          
 *                                                   ************      ************                                                            
 *                                                 ************      ************                                                              
 *                                               ************      ************                                                                
 *                                             ************      ************                                                                  
 *                                           ************      ************                                                                    
 *                                         ************      ************                                                                      
 *                                       ************      ************                                                                        
 *                                     ************      ************                                                                          
 *                                   ************      ************                                                                            
 *                                 ************      ************                                                                              
 *                               ************      ************                                                                                
 *                             ************      ************                                                                                  
 *                           ************      ************                                                                                    
 *                         ************      ************                                                                                      
 *       ****************************      ************                                                                                        
 *     ****************************      ************                                                                                          
 *   ****************************      ************                                                                                            
 * ****************************      ************                                                                                              
 * 
 * 
 * 
 * ============================================================================================================================================
 * 
 */
#include "./H_NES_Console.h"




Hbyte H_NES_IO_Read(Huint16 Address,H_NES_Console* Console){
  Hbyte r;
  Huint16 maddr;
  Huint16 Y;

  if(Address<0x4000U){
    //PPU

    maddr=Address&0x0007U;

    switch(maddr){
      case 0x7U://PPUDATA
        
        maddr=Console->PPU.Register.Internal.v;
        if((maddr&0x3F00U)==0x3F00U){
          //调色板
          r=Console->PPU.Palettes[maddr&0x001FU];
          Console->PPU.Register.PPUDATA.ReadBuffer=r;
        }else{
          r=Console->PPU.Register.PPUDATA.ReadBuffer;

          if((maddr&0x3FFFU)>0x1FFFU){
            Console->PPU.Register.PPUDATA.ReadBuffer=Console->PPU.NameTable[(maddr&0x0C00U)>>10][maddr&0x03FFU];
          }else{
            Console->PPU.Register.PPUDATA.ReadBuffer=Console->Cartridge.CHR_Read(maddr&0x3FFFU,Console);
          }
        }

        //地址更新
        if((Console->PPU.Register.Internal.IsAddXY==0)||((Console->PPU.Register.Register[vH_NES_PPU_Register_PPUMASK]&(vH_NES_PPU_PPUMASK_b|vH_NES_PPU_PPUMASK_s))==0U)){
          if((Console->PPU.Register.Register[vH_NES_PPU_Register_PPUCTRL]&vH_NES_PPU_PPUCTRL_I)==0U){
            Console->PPU.Register.Internal.v=(maddr+0x0001U)&0x3FFFU;
          }else{
            Console->PPU.Register.Internal.v=(maddr+0x0020U)&0x3FFFU;
          }
        }else{
          //X递增
          if((maddr&0x001FU)==0x001FU){
            maddr=(maddr&0xFFE0U)^0x0400U;
          }else{
            maddr+=0x0001U;
          }

          //Y递增
          if((maddr&0x7000U)==0x7000U){
            maddr&=0x0FFF;
            Y=(maddr>>5)&0x001FU;
            if(Y==0x001DU){
              maddr=(maddr&0xFC1FU)^0x0800U;
            }else if(Y==0x001FU){
              maddr=maddr&0xFC1FU;
            }else{
              maddr+=0x0020U;
            }
          }else{
            maddr+=0x1000U;
          }
          
          Console->PPU.Register.Internal.v=maddr;
        }

        return r;
      case 4U://OAMDATA
        return Console->PPU.OAM[Console->PPU.Register.Register[vH_NES_PPU_Register_OAMADDR]];
      default:
      
        if(maddr==0x0002U){
          //PPUSTATUS
          r=Console->PPU.Register.Register[maddr];
          Console->PPU.Register.Register[maddr]=r&(~vH_NES_PPU_PPUSTATUS_V);
          Console->PPU.Register.Internal.w=0x00U;
          return r;
        }else if(maddr>3){
          return Address>>8;
        }

        return Console->PPU.Register.Register[maddr];
    }
  }else{

    if(Address==0x4016U){

      if((Console->StandardController.Reg_4016_W&0x01U)!=0U){
        r=(Hbyte)Console->StandardController.SrcStatus;
        Console->StandardController.Controller1=r;
        return (r&0x01U)|0x40U;//|0x40U 用于模拟数据/地址总线的电平残留
      }
      r=Console->StandardController.Controller1;
      Console->StandardController.Controller1=r>>1;
      return (r&0x01U)|0x40U;//|0x40U 用于模拟数据/地址总线的电平残留
    }else if(Address==0x4017U){
      
      if((Console->StandardController.Reg_4016_W&0x01U)!=0U){
        r=(Hbyte)(Console->StandardController.SrcStatus>>8);
        Console->StandardController.Controller2=r;
        return (r&0x01U)|0x40U;//|0x40U 用于模拟数据/地址总线的电平残留
      }
      r=Console->StandardController.Controller2;
      Console->StandardController.Controller2=r>>1;
      return (r&0x01U)|0x40U;//|0x40U 用于模拟数据/地址总线的电平残留
    }
    
    //APU
    return H_NES_APU_Read(Address,Console);
  }
}

void H_NES_IO_Write(Hbyte Value,Huint16 Address,H_NES_Console* Console){
  Huint16 maddr;
  Huint16 Y;
  Hbyte t_byte;

  if(Address==0x4014U){
    //OAMADDR 启动DMA
    Console->CPU.DMA.OAMADDR=((Huint16)Value)<<8;
    Console->CPU.Status|=vH_NES_CPU_Status_DMA;
    return;
  }
  if(Address<0x4000U){
    //PPU

    maddr=Address&0x0007U;

    switch(maddr){
      case 0x7U://PPUDATA
        
        maddr=Console->PPU.Register.Internal.v;
        if((maddr&0x3F00U)==0x3F00U){
          //调色板
          t_byte=Value&0x3FU;
          Console->PPU.Palettes[maddr&0x001FU]=t_byte;
          if((maddr&0x0003U)==0U){
            Console->PPU.Palettes[(maddr&0x001FU)^0x0010U]=t_byte;
          }
        }else{
          if((maddr&0x3FFFU)>0x1FFFU){
            Console->PPU.NameTable[(maddr&0x0C00U)>>10][maddr&0x03FFU]=Value;
          }else{
            Console->Cartridge.CHR_Write(Value,maddr&0x3FFFU,Console);
          }
        }

        //地址更新
        if((Console->PPU.Register.Internal.IsAddXY==0)||((Console->PPU.Register.Register[vH_NES_PPU_Register_PPUMASK]&(vH_NES_PPU_PPUMASK_b|vH_NES_PPU_PPUMASK_s))==0U)){
          if((Console->PPU.Register.Register[vH_NES_PPU_Register_PPUCTRL]&vH_NES_PPU_PPUCTRL_I)==0U){
            Console->PPU.Register.Internal.v=(maddr+0x0001U)&0x3FFFU;
          }else{
            Console->PPU.Register.Internal.v=(maddr+0x0020U)&0x3FFFU;
          }
        }else{
          //X递增
          if((maddr&0x001FU)==0x001FU){
            maddr=(maddr&0xFFE0U)^0x0400U;
          }else{
            maddr+=0x0001U;
          }

          //Y递增
          if((maddr&0x7000U)==0x7000U){
            maddr&=0x0FFF;
            Y=(maddr>>5)&0x001FU;
            if(Y==0x001DU){
              maddr=(maddr&0xFC1FU)^0x0800U;
            }else if(Y==0x001FU){
              maddr=maddr&0xFC1FU;
            }else{
              maddr+=0x0020U;
            }
          }else{
            maddr+=0x1000U;
          }
          
          Console->PPU.Register.Internal.v=maddr;
        }
        break;
      case 4U://OAMDATA
        Console->PPU.OAM[Console->PPU.Register.Register[vH_NES_PPU_Register_OAMADDR]]=Value;
        break;
      case 5U://PPUSCROLL
          if(Console->PPU.Register.Internal.w==0x00U){
            Console->PPU.Register.Internal.w=0xFFU;
            Console->PPU.Register.Internal.t=(Console->PPU.Register.Internal.t&(~0x001FU))|(((Huint16)Value)>>3);
            Console->PPU.Register.Internal.x=Value&0x07U;
          }else{
            Console->PPU.Register.Internal.w=0x00U;
            Console->PPU.Register.Internal.t=(Console->PPU.Register.Internal.t&(~0x73E0U))|((((Huint16)Value)<<12)&0x7000U)|((((Huint16)Value)<<2)&0x03E0U);
          }
        break;
      case 6U://PPUADDR
          if(Console->PPU.Register.Internal.w==0x00U){
            Console->PPU.Register.Internal.w=0xFFU;
            Console->PPU.Register.Internal.t=(Console->PPU.Register.Internal.t&(~0x7F00U))|((((Huint16)Value)<<8)&0x3F00U);
          }else{
            Console->PPU.Register.Internal.w=0x00U;
            maddr=(Console->PPU.Register.Internal.t&(~0x00FFU))|((Huint16)Value);
            Console->PPU.Register.Internal.t=maddr;
            Console->PPU.Register.Internal.v=maddr;
          }
        break;
      case 0U://PPUCTRL
        Console->PPU.Register.Internal.t=(Console->PPU.Register.Internal.t&(~0x0C00U))|((((Huint16)Value)<<10)&0x0C00U);
        if(((Console->PPU.Register.Register[maddr]&0x80U)==0U)&&((Value&0x80U)!=0U)){
          if((Console->PPU.Register.Register[vH_NES_PPU_Register_PPUSTATUS]&vH_NES_PPU_PPUSTATUS_V)!=0U){
            Console->CPU.Status|=vH_NES_CPU_Status_NMI_Suspend;
          }
        }
      case 1U://PPUMASK
      case 3U://OAMADDR
        Console->PPU.Register.Register[maddr]=Value;
        break;
      default:
        break;
    }
  }else{

    if(Address==0x4016U){

      Value&=0x07U;
      Console->StandardController.Reg_4016_W=Value;
      if((Value&0x01U)!=0U){
        maddr=Console->StandardController.SrcStatus;
        Console->StandardController.Controller1=(Hbyte)maddr;
        Console->StandardController.Controller2=(Hbyte)(maddr>>8);
      }

    }else{
      //APU
      H_NES_APU_Write(Value,Address,Console);
    }
  }
}






